/*
 *    Copyright (c) 2018-2025, proj All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the proj developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: proj
 */
package com.ykht.proj.coupon.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.ykht.proj.admin.api.feign.RemoteUserService;
import com.ykht.proj.admin.api.vo.UserVO;
import com.ykht.proj.common.core.util.R;
import com.ykht.proj.common.security.util.SecurityUtils;
import com.ykht.proj.comsrv.api.feign.RemoteMsgService;
import com.ykht.proj.comsrv.vo.MsgVo;
import com.ykht.proj.coupon.Enum.WorkStateEnum;
import com.ykht.proj.coupon.config.WxPayProperties;
import com.ykht.proj.coupon.entity.*;
import com.ykht.proj.coupon.mapper.CnShopMapper;
import com.ykht.proj.coupon.mapper.FxWithdrawalMapper;
import com.ykht.proj.coupon.service.*;
import com.ykht.proj.coupon.utils.WXSignUtils;
import com.ykht.proj.coupon.vo.FxShopMoneyFlowVo;
import com.ykht.proj.coupon.vo.FxWithdrawalVo;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 提现记录表
 *
 * @author proj code generator
 * @date 2021-02-01 19:00:17
 */
@Service
public class FxWithdrawalServiceImpl extends ServiceImpl<FxWithdrawalMapper, FxWithdrawal> implements FxWithdrawalService {


	@Resource
	private FxWithdrawalMapper fxWithdrawalMapper;
	/**
	 * 提现配置表
	 */
	@Resource
	private FxConfWithdrawalService fxConfWithdrawalService;
	/**
	 * 门店资金流水
	 */
	@Resource
	private FxShopMoneyFlowService fxShopMoneyFlowService;
	/**
	 * 服务员 服务
	 */
	@Resource
	private FxWaiterExtService fxWaiterExtService;
	/**
	 * 短信
	 */
	@Resource
	private RemoteMsgService remoteMsgService;

	/**
	 * 门店
	 */
	@Resource
	private CnShopService cnShopService;
	/**
	 * 微信支付
	 */
	@Resource
	private WxPayService wxService;
	/**
	 * 用户 服务 Api
	 */
	@Resource
	private RemoteUserService remoteUserService;
	/**
	 * 企业支付 配置
	 */
	@Resource
	private WxPayProperties properties;


	/**
	 * 提现记录 分页查询(服务员，门店 ，品牌，公司)
	 *
	 * @param page
	 * @param fxWithdrawalVo
	 * @return
	 */
	@Override
	public IPage<FxWithdrawalVo> getWithdrawalListPage(Page page, FxWithdrawalVo fxWithdrawalVo) {
		return fxWithdrawalMapper.getWithdrawalListPage(page, fxWithdrawalVo);
	}

	/**
	 * 提现记录详情 的统计
	 *
	 * @param fxWithdrawalVo
	 * @return
	 */
	@Override
	public FxWithdrawalVo getWithdrawalDetailsCount(FxWithdrawalVo fxWithdrawalVo) {
		return fxWithdrawalMapper.getWithdrawalDetailsCount(fxWithdrawalVo);
	}

	/**
	 * 提现记录详情列表分页
	 *
	 * @param page
	 * @param fxWithdrawalVo
	 * @return
	 */
	@Override
	public IPage<FxWithdrawalVo> getWithdrawalDetailsListPage(Page page, FxWithdrawalVo fxWithdrawalVo) {
		return fxWithdrawalMapper.getWithdrawalDetailsListPage(page, fxWithdrawalVo);
	}

	/**
	 * 根据选择的角色 获取已经提现的佣金金额
	 *
	 * @param fxWithdrawal
	 * @return
	 */
	@Override
	public FxWithdrawalVo getSumByMoneyCount(FxWithdrawalVo fxWithdrawal) {
		return fxWithdrawalMapper.getSumByMoneyCount(fxWithdrawal);
	}

	/**
	 * 获取服务员可提现金额和已提现金额
	 *
	 * @param fxWithdrawalVo
	 * @return
	 */
	@Override
	public FxWithdrawalVo getWaiterWithdrawalCount(FxWithdrawalVo fxWithdrawalVo) {
		return fxWithdrawalMapper.getWaiterWithdrawalCount(fxWithdrawalVo);
	}

	/**
	 * 服务员提现
	 *
	 * @param fxWithdrawalVo
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	@Override
	public R getWaiterWithdrawal(FxWithdrawalVo fxWithdrawalVo) throws WxPayException {
		//  获取登录人ID
		Long userId = SecurityUtils.getUserId();
		// 获取服务员ID
		FxWaiterExt waiterExt = fxWaiterExtService.getOne(Wrappers.lambdaQuery(FxWaiterExt.class)
				.eq(FxWaiterExt::getLoginId, userId)
				.eq(FxWaiterExt::getWorkState, 1).eq(FxWaiterExt::getDelFlag, 0));

		List<Long> waiterIdList = fxWaiterExtService.getWaiterIdList();
		// 获取服务员可提现的佣金
		fxWithdrawalVo.setWaiterIdList(waiterIdList);
		FxWithdrawalVo fxWithdrawalVoIPage = this.getWaiterWithdrawalCount(fxWithdrawalVo);
		fxWithdrawalVoIPage.setSureWithdrawalMoney(fxWithdrawalVoIPage.getCumulativeMoney()
				.subtract(fxWithdrawalVoIPage.getCumulativeWithdrawalMoney()));
		if (fxWithdrawalVoIPage.getCumulativeMoney().subtract(fxWithdrawalVoIPage.getCumulativeWithdrawalMoney()).compareTo(fxWithdrawalVo.getMoney()) == -1) {
			return R.failed("可提现佣金不足~");
		}
		// 获取服务员所在的品牌单日可以提现的最高额度
		FxConfWithdrawal fxConfWithdrawal = fxConfWithdrawalService.getOne(Wrappers.lambdaQuery(FxConfWithdrawal.class)
				.eq(FxConfWithdrawal::getDelFlag, 0));
		// 获取服务员今天提现的金额
		FxWithdrawalVo fxWithdrawalVo1 = new FxWithdrawalVo();
		fxWithdrawalVo1.setWaiterIdList(waiterIdList);
		Calendar cal = Calendar.getInstance();
		fxWithdrawalVo1.setCreateStaTime(LocalDateTime.of(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE), 0, 0, 01));
		fxWithdrawalVo1.setCreateEndTime(LocalDateTime.of(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE), 23, 59, 59));
		FxWithdrawalVo fxWithdrawal = this.getWaiterWithdrawalCount(fxWithdrawalVo1);
		if (fxWithdrawal == null) {
			fxWithdrawal = new FxWithdrawalVo();
		}

		if (null != fxConfWithdrawal && fxConfWithdrawal.getMaxMoney().compareTo(fxWithdrawalVo.getMoney()
				.add(fxWithdrawal.getCumulativeWithdrawalMoney())) == -1) {
			return R.failed("您单日可提现额度已用完，请明天再来提现哦~");
		}
		// 获取本品牌下的所有服务员信息
		List<FxWaiterExt> waiterExtList = fxWaiterExtService.list(Wrappers.lambdaQuery(FxWaiterExt.class)
				.eq(FxWaiterExt::getLoginId, userId).eq(FxWaiterExt::getDelFlag, 0)
				.eq(FxWaiterExt::getBrandId, waiterExt.getBrandId())
				.in(FxWaiterExt::getWorkState, WorkStateEnum.WORK_STATE_1.getValue(),
						WorkStateEnum.WORK_STATE_2.getValue())
				.orderByAsc(FxWaiterExt::getCreateTime));
		//批次id
		String batchNumber = DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomStringUtils.random(6, "0123456789");
		List<FxWithdrawal> list = new ArrayList();
		// 判断有没有商家门店
		if (waiterExtList.size() > 0) {
			// 设置批次提现编号
			// 获取提现金额
			BigDecimal money = fxWithdrawalVo.getMoney();
			for (FxWaiterExt itme : waiterExtList) {
				FxWithdrawal tepmFxWithdrawal = null;
				if (money.compareTo(BigDecimal.ZERO) == 0) {
					break;
				}
				// 获取上家门店的余额信息
				FxWithdrawalVo fxWithdrawalVo2 = new FxWithdrawalVo();
				List<Long> waiterId = new ArrayList<>();
				waiterId.add(itme.getId());
				fxWithdrawalVo2.setWaiterIdList(waiterId);
				fxWithdrawalVo2.setShopId(itme.getShopId());
				fxWithdrawalVo2.setBrandId(itme.getBrandId());
				FxWithdrawalVo fxWithdrawa = this.getWaiterWithdrawalCount(fxWithdrawalVo2);
				if (fxWithdrawa == null) {
					fxWithdrawa = new FxWithdrawalVo();
				}
				fxWithdrawa.setSureWithdrawalMoney(fxWithdrawa.getCumulativeMoney().subtract(fxWithdrawa.getCumulativeWithdrawalMoney()));
				// 判断在上家门店是否还有余额没有提取
				if (null != fxWithdrawa && null != fxWithdrawa.getSureWithdrawalMoney()
						&& fxWithdrawa.getCumulativeMoney().subtract(fxWithdrawa.getCumulativeWithdrawalMoney())
						.compareTo(BigDecimal.ZERO) == 1) {
					// 获取门店余额 并判断余额是否大于0
					FxShopMoneyFlowVo fxShopMoneyFlowVo = fxShopMoneyFlowService.getShopBalance(itme.getShopId());
					if (null == fxShopMoneyFlowVo) {
						fxShopMoneyFlowVo = new FxShopMoneyFlowVo();
					}
					fxShopMoneyFlowVo.setRemainingSum(fxShopMoneyFlowVo.getRechargeTotal().subtract(fxShopMoneyFlowVo.getConsumeTotal()));
					if (fxShopMoneyFlowVo.getRemainingSum().compareTo(BigDecimal.ZERO) == 1) {
						// 判断提现的余额 是否小于等于 上家可以提现的余额
						if (money.compareTo(fxWithdrawa.getSureWithdrawalMoney()) < 1) {
							// 判断提现的余额 ，商家是否有充足的余额
							if (money.compareTo(fxShopMoneyFlowVo.getRemainingSum()) < 1) {
								tepmFxWithdrawal = fxShopMoneyFlowService.addWaiterWithdrawal(fxWithdrawalVo.getWithdrawalType(), itme.getCompanyId(), itme.getBrandId(),
										itme.getShopId(), itme.getId(), money,
										fxWithdrawalVoIPage.getSureWithdrawalMoney().subtract(money),
										fxWithdrawa.getSureWithdrawalMoney().subtract(money),
										1, batchNumber);
								money = BigDecimal.ZERO;
							} else {
								MsgVo msgVo = new MsgVo();
								CnShop cnShop = cnShopService.getById(itme.getShopId());
								msgVo.setMobile(cnShop.getPhone());
								msgVo.setMsg("尊敬的商户，您管理的门店" + cnShop.getName() + "账户余额不足，为不影响用户的分销提现，请及时充值！【吃哪网】");
								remoteMsgService.sendSmsCode(msgVo);
								throw new RuntimeException("请稍后再提现，商家正在马不停蹄的充值中...");
							}
						} else {
							// 判断服务员在上家门店提现的余额，上家门店余额是否充足
							if (fxWithdrawa.getSureWithdrawalMoney().compareTo(fxShopMoneyFlowVo.getRemainingSum()) < 1) {
								money = money.subtract(fxWithdrawa.getSureWithdrawalMoney());
								tepmFxWithdrawal = fxShopMoneyFlowService.addWaiterWithdrawal(fxWithdrawalVo.getWithdrawalType(), itme.getCompanyId(), itme.getBrandId(),
										itme.getShopId(), itme.getId(), fxWithdrawa.getSureWithdrawalMoney(),
										fxWithdrawalVoIPage.getSureWithdrawalMoney().subtract(fxWithdrawa.getSureWithdrawalMoney()),
										BigDecimal.ZERO, 1, batchNumber);
							} else {
								MsgVo msgVo = new MsgVo();
								CnShop cnShop = cnShopService.getById(itme.getShopId());
								msgVo.setMobile(cnShop.getPhone());
								msgVo.setMsg("尊敬的商户，您管理的门店" + cnShop.getName() + "账户余额不足，为不影响用户的分销提现，请及时充值！【吃哪网】");
								remoteMsgService.sendSmsCode(msgVo);
								throw new RuntimeException("请稍后再提现，商家正在马不停蹄的充值中...");
							}
						}
						list.add(tepmFxWithdrawal);
					}
				}
			}
			;
			// 判断提现金额是否提前完毕
			if (money.compareTo(BigDecimal.ZERO) == 1) {
				MsgVo msgVo = new MsgVo();
				CnShop cnShop = cnShopService.getById(waiterExt.getShopId());
				msgVo.setMobile(cnShop.getPhone());
				msgVo.setMsg("尊敬的商户，您管理的门店" + cnShop.getName() + "账户余额不足，为不影响用户的分销提现，请及时充值！【吃哪网】");
				remoteMsgService.sendSmsCode(msgVo);
				throw new RuntimeException("请稍后再提现，商家正在马不停蹄的充值中...");
			}
			// 企业付款到零钱
			EntPayResult entPayResult = entPay(userId, batchNumber, fxWithdrawalVo.getMoney());
//			System.out.println(entPayResult.getErrCode() + "=============================================================================================================" + entPayResult.getResultCode());
//			if (entPayResult.getResultCode().equals("FAIL")) {
//				throw new RuntimeException("佣金提现失败，请稍后重试");
//			} else if (entPayResult.getResultCode().equals("SUCCESS")) {
//				if (null != entPayResult.getErrCode() && !"".equals(entPayResult.getErrCode())
//						&& !entPayResult.getErrCode().equals("SYSTEMERROR")) {
//					throw new RuntimeException("佣金提现失败，请稍后重试");
//				} else if (null != entPayResult.getErrCode() && !"".equals(entPayResult.getErrCode()) &&
//						entPayResult.getResultCode().equals("SYSTEMERROR")) {
//					throw new RuntimeException("佣金提现失败，请联系客服");
//				}
//			}
			list.stream().forEach(o->{
				o.setWxOrder(entPayResult.getPaymentNo());//微信订单号
				o.setStatus(0);//提现成功
				o.setUpdateTime(LocalDateTime.now());
				o.setUpdateUser(SecurityUtils.getUserId());
			});
			this.updateBatchById(list);
			fxShopMoneyFlowService.addShopMoneyFlow(list);
		}
		return R.ok(true);
	}


	/**
	 * 企业付款到零钱
	 * <pre>
	 * 企业付款业务是基于微信支付商户平台的资金管理能力，为了协助商户方便地实现企业向个人付款，针对部分有开发能力的商户，提供通过API完成企业付款的功能。
	 * 比如目前的保险行业向客户退保、给付、理赔。
	 * 企业付款将使用商户的可用余额，需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
	 * 注意：与商户微信支付收款资金并非同一账户，需要单独充值。
	 * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
	 * 接口链接：https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
	 * </pre>
	 *
	 * @param userId      登录ID
	 * @param batchNumber 提现批次
	 * @param money       提现金额
	 * @return
	 * @throws WxPayException
	 */
	public EntPayResult entPay(Long userId, String batchNumber, BigDecimal money) throws WxPayException {
		UserVO userVO = remoteUserService.getByIdUser(userId);
		// 企业付款到零钱
		EntPayRequest entPay = new EntPayRequest();
		entPay.setMchAppid(properties.getMchAppid());
		entPay.setMchId(properties.getMchId());
		entPay.setDeviceInfo("");//
		entPay.setPartnerTradeNo(batchNumber);
//		entPay.setOpenid("oZv-S4qfEHHeKu5VUKeUfjEbE98o");
		entPay.setOpenid(userVO.getMiniOpenid());
		entPay.setCheckName("NO_CHECK");//
		entPay.setCheckName(properties.getCheckName());
		entPay.setReUserName("");
		entPay.setAmount(money.multiply(new BigDecimal("100")).intValue());
		entPay.setDescription("吃哪网佣金提现");//
		entPay.setSpbillCreateIp(properties.getSpbillCreateIp());//
		EntPayResult entPayResult = wxService.getEntPayService().entPay(entPay);
		System.out.println(JSONUtil.toJsonStr(entPayResult));
		return entPayResult;
	}


	/**
	 * 查询企业付款到零钱的结果
	 *
	 * @param batchNumber 商户订单号
	 * @return
	 */
	@Override
	public EntPayQueryResult queryEntPay(String batchNumber) throws WxPayException {
		return wxService.getEntPayService().queryEntPay(batchNumber);
	}

	/**
	 * 提现记录详情列表分页 的 详情明细（提现流水）
	 *
	 * @param page
	 * @param batchNumber
	 * @return
	 */
	@Override
	public IPage<FxWithdrawalVo> getWithdrawalDetailsInDetailsListPage(Page page, String batchNumber) {
		return fxWithdrawalMapper.getWithdrawalDetailsInDetailsListPage(page, batchNumber);
	}

	/**
	 * 获取服务员提现记录
	 *
	 * @param page
	 * @param fxWithdrawalVo
	 * @return
	 */
	@Override
	public IPage<FxWithdrawalVo> getWaiterWithdrawalListPage(Page page, FxWithdrawalVo fxWithdrawalVo) {
		return fxWithdrawalMapper.getWaiterWithdrawalListPage(page, fxWithdrawalVo);
	}
}
